

#include "Global.h"
#include "ModelStructTransf.h"

#include "anim.h"
#include "Bone.h"
#include "SkeletonMesh.h"
#include "SkelMeshNode.h"
#include "RigidMeshNode.h"
#include "modelrcName.h"
#include "RigidMeshNode.h"

#include "BinContainer.h"
#include "D3dModel.h"
#include "AniContainer.h"
#include "D3DAddOn.h"

#include "GameHelper.h"

int BONEPALSIZE = 28;
#define  MAXBONEID 250

BOOL GetNewBoneIDFormMap(const BYTE& byOldID,BYTE& byNewID,MapBonID& mapID)
{
	MapBonID::iterator pos = mapID.find(byOldID);
	if (pos!=mapID.end())
	{
		byNewID = pos->second;
		return TRUE;
	}
	else
	{
		return FALSE;
	}
};

BOOL GetOldBoneIDFormMap(const BYTE& byNewID,BYTE& byOldID,MapBonID& mapID)
{
	MapBonID::iterator pos = mapID.begin();
	MapBonID::iterator end = mapID.end();
	for (;pos!=end;++pos)
	{
		if (pos->second == byNewID)
		{
			byOldID = pos->first;
			return TRUE;
		}
	}
	return FALSE;	
};

BOOL CModelStructTransf::BoneIDTransfer(_BoneNode* pNewNode,_BONELIST* pOldBoneList,MapBonID& mapBonID)
{
	const char* szName = pNewNode->GetName();
	const int iOldBoneCount = pOldBoneList->nbone;

	BYTE byNewID = 0;
	BYTE byOldID = 0;
	_BONEBIN * pFindOldBoneNode = NULL;
	_BONEBIN * pOldBoneNode = NULL;
	for (int i=0;i<iOldBoneCount;++i)
	{
		pOldBoneNode = pOldBoneList->firstbone[i];
		if(strcmp(szName,pOldBoneNode->bonename) == 0)
		{
			pFindOldBoneNode = pOldBoneNode;
			break;
		}
	}
	if (pFindOldBoneNode)
	{
		byNewID = pNewNode->GetID();
		byOldID = pOldBoneNode->boneid;
		mapBonID[byOldID] = byNewID;
	}
	else
	{
		return FALSE;
	}

	_BoneNode* pNewNodeChild = NULL;
	GPOS pos = pNewNode->m_Children;
	while (pos)
	{
		pNewNodeChild = pNewNode->m_Children.GetNext(pos);
		if(!BoneIDTransfer(pNewNodeChild,pOldBoneList,mapBonID))
		{
			return FALSE;
		}
	}

	return TRUE;
}


BOOL  CModelStructTransf::BoneMapIDInit(const _ModelRCDes* pDes,MapBonID& mapBoneID)
{
	int iSKeType = GetSkMeshTypeFormMeshPart(pDes->iPartType);
	int iClass = (iSKeType == _SMESH_WEAPON || pDes->iCharType == _NPC) ? pDes->iClass : CLASS_MAX;
	int iIndex = (pDes->iCharType == _NPC) ? pDes->iIndex : 0;
	_ModelRCDes rcDes(pDes->iCharType,iSKeType,iClass,iIndex);
	CModelRCMgr<_Bone>  mgrBone(RC_BONE);	
	string strPath = CModelRCName::GetSingleton().GetFullPath(&rcDes,RC_BONE);
	_Bone* pBone = mgrBone.Load(strPath.c_str());

	if (pBone == NULL)
	{
		return FALSE;
	}

	const int iPos = strPath.find_last_not_of('.');
	strPath.replace(iPos,3,"on");
	BinContainer oldBinContain;
	_BONELIST* pOldBone =  oldBinContain.LoadBone(strPath.c_str(),0);
	if (!pOldBone)
	{
		return FALSE;
	}

	_BoneNode* pNewRootNode = pBone->GetRootNode();

	BOOL bResult = BoneIDTransfer(pNewRootNode,pOldBone,mapBoneID);
	return bResult;
	
}
CSkelMeshNode* CModelStructTransf::SkelMeshTransf(const SMeshContainer* pOld,const _ModelRCDes* pDes)
{
   MapBonID mapBoneID;
   if (!BoneMapIDInit(pDes,mapBoneID))
   {
	   return NULL;
   }

	BYTE byBoneID    = 0;
	BYTE byBoneIDTmp = 0;
	
	CSkelMeshNode* pNew = new CSkelMeshNode;

	pNew->m_uMaxFaceInfl = pOld->m_maxFaceInfl;
	pNew->m_uPattr = pOld->cpattr;

	pNew->m_vecMin = pOld->pMin;
	pNew->m_vecMax = pOld->pMax;
	pNew->m_matFCloth = pOld->fCloth;
	pNew->m_matBCloth = pOld->bCloth;

	VOID * pV = NULL;
	VOID * pI = NULL;

	pOld->pMesh->LockVertexBuffer(0,&pV);
	pOld->pMesh->LockIndexBuffer(0,&pI);

	pNew->m_uMeshFVFSize = D3DXGetFVFVertexSize(pOld->pMesh->GetFVF());
	pNew->m_uVertexCount = pOld->pMesh->GetNumVertices();
	pNew->m_uFaceCount = pOld->pMesh->GetNumFaces();
	uint32 uVertexSize = pNew->m_uVertexCount*pNew->m_uMeshFVFSize;
    uint32 uIndicesCount = pNew->m_uFaceCount*3;
	pNew->m_pVertices = new BYTE[uVertexSize];
	pNew->m_pIdices   = new WORD[uIndicesCount];
	memcpy(pNew->m_pVertices,pV,uVertexSize);
	memcpy(pNew->m_pIdices,pI,uIndicesCount*sizeof(WORD));

	pOld->pMesh->UnlockVertexBuffer();
	pOld->pMesh->UnlockIndexBuffer();

	uint32 uPart = pNew->m_uPattr;
	LPD3DXBONECOMBINATION pOldComb=reinterpret_cast<LPD3DXBONECOMBINATION>(pOld->m_pBoneCombinationBuf->GetBufferPointer());

	LPD3DXBUFFER pD3dBuf;
	D3DXCreateBuffer(sizeof(D3DXBONECOMBINATION)*uPart,&pD3dBuf);
	pNew->m_pD3DBoneCombin = reinterpret_cast<LPD3DXBONECOMBINATION>(pD3dBuf->GetBufferPointer());
	pNew->m_puD3DBoneCombinCount = new uint32[uPart];

	for (int i=0;i<uPart;++i)
	{
		pNew->m_pD3DBoneCombin[i].AttribId = pOldComb[i].AttribId ;
		pNew->m_pD3DBoneCombin[i].FaceStart = pOldComb[i].FaceStart ;
		pNew->m_pD3DBoneCombin[i].FaceCount = pOldComb[i].FaceCount ;
		pNew->m_pD3DBoneCombin[i].VertexStart = pOldComb[i].VertexStart ;
		pNew->m_pD3DBoneCombin[i].VertexCount = pOldComb[i].VertexCount ;
	
		uint32 uComBinCount = 0;
		for(int j=0;j<BONEPALSIZE;++j)
		{
			if (pOldComb[i].BoneId[j]<MAXBONEID)
			{
				uComBinCount++;
			}
		}

		pNew->m_puD3DBoneCombinCount[i] = uComBinCount;
		pNew->m_pD3DBoneCombin[i].BoneId=new DWORD[uComBinCount];

		for (int j=0;j<uComBinCount;++j)
		{
			byBoneIDTmp =  pOldComb[i].BoneId[j];
			if (!GetNewBoneIDFormMap(byBoneIDTmp,byBoneID,mapBoneID))
			{
				return NULL;
			}
			pNew->m_pD3DBoneCombin[i].BoneId[j] = byBoneID;
			int iok = 0;
		}
	}

	return pNew;
}
static int g_iBoneID = 0;
void CModelStructTransf::_BONEBIN2_BoneNode(_BoneNode* pNew,const _BONEBIN* pOld,const _Bone* pNewBone)
{
	const uint32 uSocketCount = const_cast<_Bone*>(pNewBone)->GetSocketCount();
	uint32 uBoneID = pNew->m_uID = pOld->boneid;

	for(int i=0;i<uSocketCount;++i)
	{
		if(uBoneID>const_cast<_Bone*>(pNewBone)->GetSocketNode(i)->m_uOldBoneID)
		{
			pNew->m_uID--;
		}
	}	
	assert(pNew->m_uID>=0);

	pNew->m_strName = pOld->bonename;
	pNew->m_TM      = pOld->TM;

	_BoneNode* pChlidNew = NULL;
	_BONEBIN* pChildOld = NULL;
	int iChildOld = pOld->nchild;
	for (int i=0;i<iChildOld;++i)
	{
		pChildOld = pOld->child[i];
		pChlidNew = new _BoneNode;
		_BONEBIN2_BoneNode(pChlidNew,pChildOld,pNewBone);
		pNew->m_Children.Append(pChlidNew);
	}
}
_Bone* CModelStructTransf::BoneTransf(const _BONELIST* pOld)
{
	_Bone* pNew = new _Bone;
	
	_BoundBox box;
	for (int i=0;i<pOld->BoundCount;++i)
	{
		box.m_vec3BoundBoxMin = pOld->BoundBoxMin[i];
		box.m_vec3BoundBoxMax = pOld->BoundBoxMax[i];
		pNew->m_vecBoundBox.push_back(box);
	}

	_BONEBIN* pRootBoneOld = NULL;
	_BONEBIN* pDummy = NULL;
	uint32 uSocketID = 0; 
	_ModelSocket modelsocket;
	int iBoneCount = pOld->nbone;
	for (int i=0;i<iBoneCount;++i)
	{
		if (pRootBoneOld)
		{
			if (pOld->firstbone[i]->parent == NULL)
			{
				pDummy = pOld->firstbone[i];
				modelsocket.m_uID = uSocketID++;
				modelsocket.m_strName = pDummy->bonename;
				modelsocket.m_TM      = pDummy->TM;
				modelsocket.m_uOldBoneID = pDummy->boneid;
				pNew->m_vecSocket.push_back(modelsocket);
			}
		}
		else
		{
			if (pOld->firstbone[i]->parent == NULL)
			{
				pRootBoneOld = pOld->firstbone[i];		
			}
		}
		
	}

	if (pRootBoneOld)
	{
		g_iBoneID = 0;
		_BONEBIN2_BoneNode(&pNew->m_RootBoneNode,pRootBoneOld,pNew);
	}
	else
	{
		delete pNew;
		pNew = NULL;
	}

	return pNew;
}
_Anim* CModelStructTransf::AnimTransf(const ANILIST* pOld,const _ModelRCDes* pDes)
{

	MapBonID mapBoneID;
	if (!BoneMapIDInit(pDes,mapBoneID))
	{
		return NULL;
	}

	int iSKeType = GetSkMeshTypeFormMeshPart(pDes->iPartType);
	int iClass = (iSKeType == _SMESH_WEAPON || pDes->iCharType == _NPC) ? pDes->iClass : CLASS_MAX;
	int iIndex = (pDes->iCharType == _NPC) ? pDes->iIndex : 0;
	_ModelRCDes rcDes(pDes->iCharType,iSKeType,iClass,iIndex);

	CModelRCMgr<_Bone>  mgrBone(RC_BONE);	
	string strPath = CModelRCName::GetSingleton().GetFullPath(&rcDes,RC_BONE);
	_Bone* pBone = mgrBone.Load(strPath.c_str());

	if (pBone == NULL)
	{
		return NULL;
	}

	_Anim* pNew      = new _Anim;
	pNew->InitAniList(pBone->GetBoneCount(),pBone->GetSocketCount());

	BYTE byFPS = (pOld->attr.FPS>0) ? pOld->attr.FPS : 30;
	pNew->m_Attr.Blend   = pOld->attr.Blend;
	pNew->m_Attr.byFPS   = byFPS;

	pNew->m_strName      =  CModelRCName::GetSingleton().GetModelRCName(pDes,RC_ANIM);
	pNew->m_BShare       = pOld->share;

	if (pDes->iPartType == _BODY)
	{	
		AddAniEvent( pOld->attr, pNew );

		_AnimEvent* pEvent;
		for (int i=0;i<pOld->attr.ChangeCount;++i)
		{
			pEvent = new _AnimEvent;
			pEvent->m_fTime = pOld->attr.m_ArmChange[i].Changetime;
			pEvent->m_dwData = pOld->attr.m_ArmChange[i].ChangePart;
			pEvent->m_byEventType = _EVENT_WEAPONCHANGE;
			pEvent->m_byFlag = _FLAG_ANI_1;
			pNew->m_listEvent.Append(pEvent);
		}
	}

	ANILISTitem* pOldItem    = NULL;

	if (pOld->aniType == TYPE_GENERALANI)
	{
		pOldItem = const_cast<ANILISTitem*>(pOld->keys);
	}
	else if (pOld->aniType == TYPE_FACEANI)
	{
		pOldItem = const_cast<ANILISTitem*>(pOld->facekeys);
	}
	else
	{
		pOldItem = const_cast<ANILISTitem*>(pOld->weaponkeys);
	}
	int iOldBoneCount = pOld->nbone;

	_BoneNode* pTmpBoneNode = NULL;
	_ModelSocket* pTmpSocket = NULL;
	_AnimKeyList* pAnimList = NULL;
	uint32 uNewBoneID = 0;
	int iPos = 0;
	int iRot = 0;

	float fMaxAnimTime = 0.0f;
	BYTE byOldID = 0;
	for (int i = 0;i < iOldBoneCount;++i)
	{
		if (!strlen(pOldItem[i].bonename))
		{
			continue;
		}

		pTmpBoneNode = const_cast<_BoneNode*>(pBone->GetBoneNode(pOldItem[i].bonename));
		if (pTmpBoneNode )
		{
			pAnimList  = pNew->m_pAnimKeyList;
			uNewBoneID = pTmpBoneNode->m_uID;
		}
		else 
		{
			pTmpSocket = const_cast<_ModelSocket*>(pBone->GetSocketNode(pOldItem[i].bonename));
			if (pTmpSocket)
			{
				pAnimList  = pNew->m_pAnimSocket;
				uNewBoneID = pTmpSocket->m_uID;
			}
			else
			{
				//prtLOG("%s is not present!",pOldItem[i].bonename);
				continue;
			}
		}

		if (!GetOldBoneIDFormMap(uNewBoneID,byOldID,mapBoneID))
		{
			continue;
		}
		
		pAnimList[uNewBoneID].m_strName   = pOldItem[byOldID].bonename;
		pAnimList[uNewBoneID].m_matOffset = pOldItem[byOldID].offset;
		iPos = pOldItem[byOldID].npos;//index = 0 set time 0xffff
		iRot = pOldItem[byOldID].nrot;

		if (iPos>0)
		{
			//prtLOG("%s position count = %d!",pOldItem[i].bonename,iPos);
			pAnimList[uNewBoneID].m_uPosKeyCount = iPos;
			pAnimList[uNewBoneID].m_pPosKey  = new _PosKey[iPos];
			for(int n=0;n<iPos;++n)
			{
				pAnimList[uNewBoneID].m_pPosKey[n].fTime = (float)pOldItem[byOldID].pos[n+1].dwTime;
				pAnimList[uNewBoneID].m_pPosKey[n].vPos   = pOldItem[byOldID].pos[n+1].vPos;

				if (fMaxAnimTime<pAnimList[uNewBoneID].m_pPosKey[n].fTime)
				{
					fMaxAnimTime = pAnimList[uNewBoneID].m_pPosKey[n].fTime;
				}
			}
		}
		if (iRot>0)
		{
			//prtLOG("%s rotation count = %d!",pOldItem[i].bonename,iRot);			
			pAnimList[uNewBoneID].m_uRotKeyCount = iRot;
			pAnimList[uNewBoneID].m_pRotateKey = new _RotateKey[iRot];
			for(int n=0;n<iRot;++n)
			{
				pAnimList[uNewBoneID].m_pRotateKey[n].fTime = (float)pOldItem[byOldID].rot[n+1].dwTime;
				pAnimList[uNewBoneID].m_pRotateKey[n].quat   = pOldItem[byOldID].rot[n+1].quat;

				if (fMaxAnimTime<pAnimList[uNewBoneID].m_pRotateKey[n].fTime)
				{
					fMaxAnimTime = pAnimList[uNewBoneID].m_pRotateKey[n].fTime;
				}
			}			
		}				
	}

	if (fMaxAnimTime>1.0f)
	{
		pNew->m_uMaxTime = fMaxAnimTime;
	}
	else
	{
		delete pNew;
		pNew = NULL;
	}

	return pNew;
}
void CModelStructTransf::AddAniEvent( const ANIATTR_VER2& attr, _Anim* pNew )
{
	_AnimEvent* pEvent;
	for (int i=0;i<attr.nhit;++i)
	{

		pEvent = new _AnimEvent;
		pEvent->m_fTime = attr.hitPoint[i].start;
		pEvent->m_dwData = FilterData( attr.hitPoint[i].dataIndex );
		pEvent->m_byEventType = ConvertEventType( attr.hitPoint[i].type, true );
		pNew->m_listEvent.Append(pEvent);

		if( -1 == attr.hitPoint[i].end )
			continue;
		pEvent = new _AnimEvent;
		pEvent->m_fTime = attr.hitPoint[i].end;
		pEvent->m_dwData = FilterData( attr.hitPoint[i].dataIndex );
		pEvent->m_byEventType = ConvertEventType(attr.hitPoint[i].type, false );
		pNew->m_listEvent.Append(pEvent);
	}
}

int CModelStructTransf::ConvertEventType( int oldEventType, bool isStart )
{
	if( oldEventType == Event_HitPoint && isStart )
	{
		return _EVENT_HITSTART;
	}
	else if ( oldEventType == Event_HitPoint )
	{
		return _EVENT_HITEND;
	}
	else if ( oldEventType == Event_Sound )
	{
		return _EVENT_SOUND;
	}
	else if ( oldEventType == Event_Effect )
	{
		return _EVENT_EFFECT;
	}
}
CRigidMeshNode* CModelStructTransf::RigidMeshTransf(const AddOnContainer* pOld,const _ModelRCDes* pDes)
{
	CRigidMeshNode* pNew = new CRigidMeshNode;
	pNew->m_pD3DMesh = pOld->mesh;
	pNew->m_uVertexCount = pOld->mesh->GetNumVertices();
	pNew->m_uFaceCount = pOld->mesh->GetNumFaces();
	pNew->m_vecMax = pOld->attr.pMax;
	pNew->m_vecMin = pOld->attr.pMin;

	return pNew;
}

void _ModelDesFormMESHINFO(_ModelRCDes& NewOut,const MESHINFO& OldIn)
{
	NewOut.iCharType = OldIn.sex;
	NewOut.iPartType = OldIn.part;
	NewOut.iClass    = OldIn._class;
	NewOut.iIndex    = OldIn.index;
}


void CModelStructTransf::SaveSkelMesh(const _ModelRCDes* pDes,CSkelMeshNode* pMesh)
{
	CModelRCMgr<CSkelMeshNode>  mgrMesh(RC_MESH);	
	string strPath = CModelRCName::GetSingleton().GetFullPath(pDes,RC_MESH);
	mgrMesh.Save(strPath.c_str(),pMesh);
}

void CModelStructTransf::SaveBone(const _ModelRCDes* pDes,_Bone* pBone)
{
	CModelRCMgr<_Bone>  mgrBone(RC_BONE);	
	string strPath = CModelRCName::GetSingleton().GetFullPath(pDes,RC_BONE);
	mgrBone.Save(strPath.c_str(),pBone);
}
void CModelStructTransf::SaveAnim(const _ModelRCDes* pDes,_Anim* pAnim)
{
	CModelRCMgr<_Anim>  mgrAnim(RC_ANIM);
	string strPath = CModelRCName::GetSingleton().GetFullPath(pDes,RC_ANIM);
	mgrAnim.Save(strPath.c_str(),pAnim);
}

void CModelStructTransf::SaveRigidMesh(const _ModelRCDes* pDes,CRigidMeshNode* pMesh,const int& eRCType)
{
	_ModelRCType type = static_cast<_ModelRCType>(eRCType);
	CModelRCMgr<CRigidMeshNode>  mgrMesh(type);	
	string strPath = CModelRCName::GetSingleton().GetFullPath(pDes,type);
	mgrMesh.Save(strPath.c_str(),pMesh);
}
void CModelStructTransf::TransfAndSaveSkelMesh(const SMeshContainer* pOld,const MESHINFO* pInfor)
{
	_ModelRCDes rcDes(pInfor->sex,pInfor->part, pInfor->_class,pInfor->index);
	CSkelMeshNode* pNew = SkelMeshTransf(pOld,&rcDes);
	if (pNew)
	{
		SaveSkelMesh(&rcDes,pNew);
		delete pNew;
	}	
}

void CModelStructTransf::TransfAndSaveRigidMesh(const AddOnContainer* pOld,const MESHINFO* pInfor,const int& eRCType)
{
	_ModelRCDes rcDes(pInfor->sex,pInfor->part, pInfor->_class,pInfor->index);
	CRigidMeshNode* pNew = RigidMeshTransf(pOld,&rcDes);
	if (pNew)
	{
		SaveRigidMesh(&rcDes,pNew,eRCType);
		delete pNew;
	}	
}
void CModelStructTransf::TransfAndSaveBone(const _BONELIST* pOld,const BONEINFO* pInfor)
{
	_ModelRCDes rcDes(pInfor->sex,pInfor->type, pInfor->_class,pInfor->index);
	_Bone* pNew = BoneTransf(pOld);
	if (pNew)
	{
		SaveBone(&rcDes,pNew);
		delete pNew;
	}

}
void CModelStructTransf::TransfAndSaveAnim(const ANILIST* pOld,const MESHINFO* pInfor,const int& iIndexEx)
{
	_ModelRCDes rcDes(pInfor->sex,pInfor->part, pInfor->_class,pInfor->index,iIndexEx);
	_Anim* pNew = AnimTransf(pOld,&rcDes);
	if (pNew)
	{
		SaveAnim(&rcDes,pNew);
		delete pNew;
	}
	
}